# koroFileHeader at Yungoal acer
# Create: 2021-04-25 16:31:23
# LastEdit: 2024-07-26 17:26:52
"""
处理Resource Graph返回的结果时：
请求时参数是 result_format="objectArray"，只处理objectArray格式，不处理Table格式。

被引用:
- models.py
"""
__author__ = '749B'


from dateutil.parser import parse
import os
import re

from typing import Dict, List, Tuple, Mapping, Optional

# Typing.
_Data = List[Dict[str, str]]

def output_csv(
    data: _Data,
    comma_begin: bool = False,
    column_map: Mapping[str, str] = None,
    ignores: List[str] = None,
    ) -> None:
    """
    适应蓝鲸作业平台，导出执行日志的功能。导出的文件，每行开头都会有服务器地址。
    为适应这个格式，在每行开头都加个逗号隔开。
    开关参数：comma_begin=True
    """
    column_map = {} if column_map is None else column_map
    ignores = [] if ignores is None else ignores

    # 忽略指定的key
    columns = [k for k in data[0].keys() if k not in ignores]
    
    # 按 column_map 为字段改名
    for k, v in column_map.items():
        if k in columns:
            index = columns.index(k)
            columns.remove(k)
            columns.insert(index, v)
            
    line = ','.join(columns)
    line = ','+line if comma_begin else line
    print(line)

    # 如果是Jenkins环境，直接写到工作空间
    if 'JENKINS_HOME' in os.environ and os.environ.get('WORKSPACE'):
        csv_file = os.path.join(os.environ.get('WORKSPACE'), 'output.csv')
        with open(csv_file, 'w', encoding='utf-8-sig') as f:
            f.write(line + '\n')
            for row in data:
                line = ','.join([str(v) for k, v in row.items() if k not in ignores])
                line = ','+line if comma_begin else line
                print(line)
                f.write(line + '\n')
    else:
        for row in data:
            line = ','.join([str(v) for k, v in row.items() if k not in ignores])
            line = ','+line if comma_begin else line
            print(line)

def parse_time(data: _Data) -> None:
    """解决时区问题
    逐条用正则匹配字符串，匹配到UTC的时间格式，就转换为当地时间
    """
    def is_utc_timestr(timestr: str) -> Optional[re.Match]:
        """正则完全匹配UTC时间字符串"""
        if not isinstance(timestr, str):  
            # 非字符串直接返回None，逻辑同不匹配一样
            return
        pattern = '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]+Z'
        return re.fullmatch(pattern, timestr)

    for item in data:
        for k, v in item.items():
            if is_utc_timestr(v):
                local_timestr = parse(v).astimezone().strftime("%Y-%m-%dT%H:%M:%SZ%z")
                item[k] = local_timestr

def recovery_vault_name(data: _Data, key='properties_policyId') -> None:
    """从properties_policyId的值中，提取RecoveryVaultName
    将原来对象中的properties_policyId删除，
    添加RecoveryVaultName的数据
    """
    for item in data:
        value = item.pop(key)
        if value:
            item['RecoveryVaultName'] = value.split('/')[8]
        else:
            item['RecoveryVaultName'] = ''
        
def runcmd_parse_output(value: _Data) -> Tuple[str, str]:
    """解析 run command 返回的结果
    直接传入 properties.output.value 的值
    """
    std_out, std_err = None, None
    for v in value:
        code = v.get('code')
        if not code:
            continue
        if code == 'ComponentStatus/StdOut/succeeded':
            std_out = v.get('message')
        elif code == 'ComponentStatus/StdErr/succeeded':
            std_err = v.get('message')
        elif code == 'ProvisioningState/succeeded':
            _, out_err = v.get('message').split('\n[stdout]\n', 1)
            std_out, std_err = out_err.split('\n[stderr]\n')
    return std_out, std_err
